from django.test import TestCase

# Create your tests here.
from django.test import TestCase, tag
from rest_framework.test import APITestCase,APITransactionTestCase
# Create your tests here.
from .models import *
from .serializers import ShopOrderSerializer
from accounts.models import User,Address
import random

class MixinMockUser:
    user = None

    def _mock_user_data(self):
        data = {
            "username": "username_1",
            "password": "password_1",
            "mobile": "mobile_1",
        }
        self.user = User.objects.create_user(**data)
        self.address = Address.objects.create(
            user=self.user,
            name="Gavin",
            tel="11111",
            street="中国。北京"
        )


class MixinMockProduct:

    def _mock_product(self):
        new_cate = Category.objects.create(title="新的分类")

        self.mock_data = []  # 保存的是存在的数据
        for i in range(3):
            product = Product.objects.create(title=f"新的标题{i} {random.randint(1,10)}",
                                             category=new_cate,
                                             price=Decimal("600"),
                                             gender=2,
                                             type=1
                                             )
            self.mock_data.append(product)
            style = ProductStyle.objects.create(
                product=product,
                title="xxx",
                img="xxxxxxx"
            )
            self.product = product
            self.style = style


class MixinMockShopCart:

    def _mock_cart_cart(self):
        self.cart = ShopCart.objects.create(
            user=self.user,
            product=self.product,
            style=self.style,
            size="s",
        )



class ProductTest(APITestCase):

    def setUp(self):
        # 创建假数据，准备测试环境
        new_cate = Category.objects.create(title="新的分类")

        self.mock_data = [] # 保存的是存在的数据
        for i in range(3):
            self.mock_data.append(
                Product.objects.create(title=f"新的标题{i} {random.randint(1,10)}",
                                       category=new_cate,
                                       price=Decimal("600"),
                                       gender=2,
                                       type=1)
            )
            pass

    def test_detail(self):
        """
        测试商品详情的API
        :return:
        """

        for obj in self.mock_data:  # 遍历数据库中数据

            # 1. 接口访问正常
            url = f"/store/product/{obj.id}/"  # obj.id 存在的商品id
            response = self.client.get(url)
            self.assertEqual(response.status_code, 200, "详情页API访问失败")  # 输入错正确的id，响应404
            # 404 url 没有设置，或者设置错了。 检查路由

            # 2. 接口返回内容正确
            content = response.data  # 接口返回内容
            content_str = str(response.data)
            key_list = [
                obj.get_gender_display(), # 1. 性别
                obj.get_type_display(), # 2. 类型
                obj.category.title, # 3. 分类
                obj.title, # 5. 标题
                obj.price,  # 5. 价格
                obj.sales_price,  # 5. 价格
                # 5. 其他。。。。
            ]

            for k in key_list:

                # if not str(k) in content_str:
                #     print("内容不正确，测试失败")  # 如果你要表现测试失败，请手机用断言
                self.assertTrue(str(k) in content_str, f'{k} not in content_str')

class ShopCartTest(MixinMockShopCart, MixinMockProduct, MixinMockUser, APITransactionTestCase):
    base_url = "/store/cart"

    def setUp(self):
        # 创建假数据，准备测试环境

        self._mock_product()
        # mock user
        self._mock_user_data()
        # mock cart
        self._mock_cart_cart()

        self.client.force_login(self.user)

    def test_list(self):
        url = self.base_url + '/'
        response = self.client.get(url)

        self.assertEqual(response.status_code, 200)

    def test_put(self):
        # todo mock 购物车数据

        self.cart.count = 10  # 购物车数量=10
        self.cart.save()

        url = self.base_url + f'/{self.cart.id}/'
        response = self.client.get(url)

        self.assertEqual(response.status_code, 200)
        self.assertEqual(response.data['count'], 10)

        response = self.client.patch(url, {"count": 1})  # 修改数据的请求
        self.assertEqual(response.status_code, 200)

        #
        response = self.client.get(url)

        self.assertEqual(response.status_code, 200)
        self.assertEqual(response.data['count'], 1)

    def test_delete(self):
        # todo mock 购物车数据
        url = self.base_url + f'/{self.cart.id}/'
        response = self.client.get(url)
        self.assertEqual(response.status_code, 200)

        response = self.client.delete(url)
        self.assertEqual(response.status_code, 204)  # 删除成功，没有数据可以返回

        response = self.client.get(url)
        self.assertEqual(response.status_code, 404)

    def test_new(self):
        # - 同样款式的商品，第一次添加创建数据，第二次添加时，不需要创造
        # - POST / cart / {模型字段}
        url = self.base_url + '/'
        data = {
            "product": self.product.id,
            "style": self.style.id,
            "size": "S",
            "count": random.randint(1, 10),
        }
        # - 删除所有的数据
        ShopCart.objects.all().delete()
        # - 第一次查询数据库的数量
        queryset = ShopCart.objects.all()
        count_1 = queryset.count()
        # - 第一次添加：
        response = self.client.post(url, data)
        # - 接口返回201
        self.assertEqual(response.status_code, 201)
        # - 数据库里，增加了数据（ 第二次查询数据库的数量，比上一次多)
        count_2 = queryset.count()
        obj_2 = queryset.last()
        self.assertGreater(count_2, count_1)
        self.assertEqual(count_2 - 1, count_1)

        # - 第二次添加：
        response = self.client.post(url, data)
        # - 接口返回201
        self.assertEqual(response.status_code, 201)
        # - 数据库，不增加数据 （ 第三次查询数据库的数量，和第二次一样）
        count_3 = queryset.count()
        obj_3 = queryset.last()
        self.assertEqual(count_3, count_2)

        # 修改已有数据的数量字段
        self.assertNotEqual(obj_2.count, obj_3.count)


class ShopOrderTest(MixinMockShopCart, MixinMockProduct, MixinMockUser, APITransactionTestCase):
    base_url = "/store/order"

    def setUp(self):
        # 创建假数据，准备测试环境
        self._mock_product()
        # mock user
        self._mock_user_data()
        # mock cart
        self._mock_cart_cart()

        self.client.force_login(self.user)

    def test_new(self):
        url = self.base_url + '/'
        data = {
            "addr": self.address.id,  # 收货地址的id
            "item_list": [self.cart.id, ],

        }
        pass
        #     1. 必须选择收货地址， 如果没有，返回400
        response = self.client.post(url, {**data, **{"addr": ""}})
        self.assertEqual(response.status_code, 400)
        #         1. 收货地址必须存在
        #         2. 收货地址必须时当前用户
        #     # 2. 必须选择购物车条目，如果没有或者错误，返回400
        response = self.client.post(url, {**data, **{"item_list": []}})
        self.assertEqual(response.status_code, 400)
        #     1. 购物车条目，必须时存在的
        #     2. 购物车条目，必须时当前用户
        # 3. 输入正确的数据生成订单，订单数量、种类， 应该和购物车一致
        response = self.client.post(url, {**data, })
        self.assertEqual(response.status_code, 201, response.data)

        order = ShopOrder.objects.last()  # 返回最新创建的订单
        item_list = ShopItem.objects.filter(order=order)  # 返回该订单商品清单
        self.assertEqual(len(item_list), len(data['item_list']))
        item = item_list[0]

        self.assertEqual(self.cart.product, item.style.product)
        self.assertEqual(self.cart.style, item.style)
        self.assertEqual(self.cart.size, item.size)
        self.assertEqual(self.cart.count, item.count)

        # 4. 订单创建成功，对应的商品，从购物车移除
        with self.assertRaises(ShopCart.DoesNotExist):
            # 断言此处由异常
            ShopCart.objects.get(id=self.cart.id)
            # 重新获取购物车条目，发现 数据不存在


    def test_list(self):
    #         - 列出所有的订单， 列表接口 200 []
        url = self.base_url + '/'
        response=self.client.get(url)
        self.assertEqual(response.status_code,200)
        queryset=ShopItem.objects.all()
        serializer=ShopOrderSerializer(queryset,many=True)
        self.assertEqual(response.data,serializer.data)

    def test_id(self):
        #         - 筛选订单， 接口过滤
        #         - 获取订单详情， 详情接口 404
        for obj in self.mock_data:
            url = self.base_url +f"/{obj.id}/"
            response = self.client.get(url)
            self.assertEqual(response.status_code, 404)

    #         - 查询购物车中，选中的内容 （1， 选中， 2筛选）